﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;

namespace Ehai.Web.Framework
{
    class CalcByExpression
    {
        #region 计算函数

        //中序转换成后序表达式再计算
        // 如：23+56/(102-100)*((36-24)/(8-6))
        // 转换成：23|56|102|100|-|/|*|36|24|-|8|6|-|/|*|+"
        //以便利用栈的方式都进行计算。
        /// <summary>
        /// 计算函数
        /// </summary>
        /// <param name="Expression">包含算式的字符串</param>
        /// <exception cref="Ehai.Web.Framework.WebException">
        /// 没有对异常进行处理，可能抛出异常
        /// </exception>
        /// <returns>返回计算后的结果(字符串类型)</returns>
        public static string Calculate(string Expression)
        {

            Expression = Expression.Replace(" ", "");
            Expression = Regex.Replace(Expression, @"([\+\-\*\\\(\)])([\+\-][0-9\.]+)|(^[\+\-][0-9\.]+)", new MatchEvaluator(addZero));

            ArrayList operatorList = new ArrayList();
            string oper1, ExpressionString = String.Empty, oper3;

            while (Expression.Length > 0)
            {
                oper3 = String.Empty;

                //取数字处理
                if (Char.IsNumber(Expression[0]))
                {
                    while (Char.IsNumber(Expression[0]) || Expression[0] == '.')
                    {
                        oper3 += Expression[0].ToString();
                        Expression = Expression.Substring(1);

                        if (Expression == String.Empty) break;
                    }
                    ExpressionString += oper3 + "|";
                }

                //取“C”处理
                if (Expression.Length > 0 && Expression[0].ToString() == "(")
                {
                    operatorList.Add("(");
                    Expression = Expression.Substring(1);
                }

                //取“)”处理
                oper3 = String.Empty;
                if (Expression.Length > 0 && Expression[0].ToString() == ")")
                {
                    do
                    {

                        if (operatorList[operatorList.Count - 1].ToString() != "(")
                        {
                            oper3 += operatorList[operatorList.Count - 1].ToString() + "|";
                            operatorList.RemoveAt(operatorList.Count - 1);
                        }
                        else
                        {
                            operatorList.RemoveAt(operatorList.Count - 1);
                            break;
                        }

                    } while (true);
                    ExpressionString += oper3;
                    Expression = Expression.Substring(1);
                }

                //取运算符号处理
                oper3 = "";
                if (Expression.Length > 0 && (Expression[0].ToString() == "*" || Expression[0].ToString() == "/" || Expression[0].ToString() == "+" || Expression[0].ToString() == "-"))
                {
                    oper1 = Expression[0].ToString();
                    if (operatorList.Count > 0)
                    {

                        if (operatorList[operatorList.Count - 1].ToString() == "(" || verifyOperatorPriority(oper1, operatorList[operatorList.Count - 1].ToString()))
                        {
                            operatorList.Add(oper1);
                        }
                        else
                        {
                            oper3 += operatorList[operatorList.Count - 1].ToString() + "|";
                            operatorList.RemoveAt(operatorList.Count - 1);
                            operatorList.Add(oper1);
                            ExpressionString += oper3;

                        }

                    }
                    else
                    {
                        operatorList.Add(oper1);
                    }

                    Expression = Expression.Substring(1);
                }
            }

            oper3 = String.Empty;
            while (operatorList.Count != 0)
            {
                oper3 += operatorList[operatorList.Count - 1].ToString() + "|";
                operatorList.RemoveAt(operatorList.Count - 1);
            }

            ExpressionString += oper3.Substring(0, oper3.Length - 1); ;


            return calcByExpressionEx(ExpressionString);

        }

        private static string addZero(Match m)
        {
            return m.Groups[3].Value == String.Empty ? m.Groups[1].Value + "(0" + m.Groups[2].Value + ")" : "(0" + m.Groups[3].Value + ")";
        }

        // 第二步:把转换成后序表达的式子计算
        //23|56|102|100|-|/|*|36|24|-|8|6|-|/|*|+"
        private static string calcByExpressionEx(string Expression)
        {
            //定义两个栈
            ArrayList dataList = new ArrayList();
            //dataList.Add("0");

            float oper1, oper2;
            string[] arrOper = Expression.Split(Convert.ToChar("|"));

            for (int i = 0; i < arrOper.Length; i++)
            {
                if (Char.IsNumber(arrOper[i], 0))
                {
                    dataList.Add(arrOper[i]);
                }
                else
                {
                    //两个操作数退栈和一个操作符退栈计算
                    oper2 = (float)Convert.ToDouble(dataList[dataList.Count - 1]);
                    dataList.RemoveAt(dataList.Count - 1);

                    oper1 = (float)Convert.ToDouble(dataList[dataList.Count - 1]);
                    dataList.RemoveAt(dataList.Count - 1);
                    dataList.Add(operatorTwoNumber(oper1, oper2, arrOper[i]));
                }

            }


            return dataList[0].ToString();
        }


        //判断两个运算符优先级别
        private static bool verifyOperatorPriority(string Operator1, string Operator2)
        {

            if (Operator1 == "*" && Operator2 == "+")
                return true;
            else if (Operator1 == "*" && Operator2 == "-")
                return true;
            else if (Operator1 == "/" && Operator2 == "+")
                return true;
            else if (Operator1 == "/" && Operator2 == "-")
                return true;
            else
                return false;
        }

        //计算
        private static float operatorTwoNumber(float operand1, float operand2, string operator2)
        {
            switch (operator2)
            {
                case "*":
                    operand1 *= operand2;
                    break;
                case "/":
                    operand1 /= operand2;
                    break;
                case "+":
                    operand1 += operand2;
                    break;
                case "-":
                    operand1 -= operand2;
                    break;
                default:
                    break;
            }
            return operand1;
        }

        #endregion

    }
}
